import sublime, sublime_plugin
import os
import subprocess, threading
import time
import re


class MessageProgress(threading.Thread):

	def __init__(self, window, message, done_message):
		super().__init__()
		self.window = window
		self.view = window.active_view()
		self.message = message
		self.done_message = done_message
		self.size = 10
		self.before = 0
		self.stop = False


	def run(self):
		while self.stop != True:
			self.before = (self.before + 1) % self.size
			after = self.size - self.before
			if self.view.is_valid():
				self.view = self.window.active_view()
			self.view.set_status('cmake','%s [%s>%s]' % (self.message, ' ' * self.before, ' ' * after))
			time.sleep(0.1)
		if self.stop:
			self.view.set_status('cmake', self.done_message)

	def terminate(self):
		self.stop = True


def show_files(path, all_item):
    # 首先遍历当前目录所有文件及文件夹
    file_list = os.listdir(path)
    # 准备循环判断每个元素是否是文件夹还是文件，是文件的话，把名称传入list，是文件夹的话，递归
    for file in file_list:
        # 利用os.path.join()方法取得路径全名，并存入cur_path变量，否则每次只能遍历一层目录
        cur_path = os.path.join(path, file)
        all_item.append(cur_path.replace('\\', '/'))
        # 判断是否是文件夹
        if os.path.isdir(cur_path):
            show_files(cur_path, all_item)
    return all_item


class ViewAddLine(sublime_plugin.TextCommand):
    def run(self, edit, line, doScroll):
        # force a scroll to the end if the last line is currently visible
        force_scroll = False
        if doScroll and self.view.visible_region().contains(self.view.size()):
            force_scroll = True

        self.view.run_command("append", { "characters": line, "force": True })

        if force_scroll:
            self.view.run_command("move_to", { "to": "eof", "extend": False })


class FindCommand(sublime_plugin.WindowCommand):
	def run(self):
		self.window.show_input_panel("file name:", "", self.on_set_name_done, None, None)



	def on_set_name_done(self, finder_name):
		t = MessageProgress(sublime.active_window(), "finding: " + finder_name, "find done!")
		t.start()

		def task():
			all_item = []
			folders = self.get_project_path()
			if folders is None:
				return
			for f in folders:
				show_files(f, all_item)
			result = self.find_all(finder_name, all_item)
			result_view = sublime.active_window().new_file()
			result_view.set_name("search : "+finder_name)
			result_view.set_scratch(True)
			result_view.set_read_only(True)
			result_view.run_command("view_add_line", {"line": "search for: '"+ finder_name + "' in: [" + ','.join(folders) + "]\n", "doScroll": True})
			for item in result:
				if result_view.is_valid():
					result_view.run_command("view_add_line", {"line": item + "\n", "doScroll": True})
				else:
					t.terminate()
					print('terminated search!')
					break
			t.terminate()
		threading.Thread(target = task).start()


	def fuzzy_match(self, user_input, collection):
		suggestions = []
		pattern = '.*?'.join(user_input)    # Converts 'djm' to 'd.*?j.*?m'
		regex = re.compile(pattern)         # Compiles a regex.
		for item in collection:
			match = regex.search(item)      # Checks if the current item matches the regex.
			if match:
				suggestions.append((len(match.group()), match.start(), item))
		return [x for _, _, x in sorted(suggestions)]

	def find_all(self, user_input, collection):
		result = []
		for item in collection:
			if user_input in item:
				result.append(item)

		return result


	def get_project_path(self):
		project_folders = self.window.folders()
		print(project_folders)
		if len(project_folders) == 0:
			return None
		else:
			dir_list = []
			for i in project_folders:
				path = i.replace('\\', '/')
				dir_list.append(path)
			return dir_list


#右键打开文件
class OpenCommand(sublime_plugin.TextCommand):

	def run(self, edit):
		sels = self.view.sel()
		if len(sels) > 0 :
			sels = sels[0]
		regionStr = self.view.substr(sels)
		if os.path.exists(regionStr) and not os.path.isdir(regionStr):
			sublime.active_window().open_file(regionStr)
		else:
			self.view.set_status('open:', "cannot find file:" + regionStr)


def highlight_key(view):
    """
    make region keys incremental and recyclable
    """
    value = view.settings().get("finder.highlight_counter", 0)

    if value == 1e8:
        value = 0

    while value >= 1:
        regions = view.get_regions("finder#{}".format(value))
        if regions and not regions[0].empty():
            break
        value -= 1
    value += 1
    view.settings().set("finder.highlight_counter", value)
    return "finder#{}".format(value)


URL_POPUP = """
<style>
	body {
	    margin: 0px;
	    padding: 0px;
	}
	div {
	    border: 1px;
	    border-style: solid;
	    border-color: grey;
	}
</style>
<body>
	<div>
		<a href="open">
			<img width="20%" height="20%" src="res://Packages/find_in_project/images/link.png" />
		</a>
	</div>
</body>
"""

rex = re.compile(r'''[a-zA-Z]:/((?:[a-zA-Z0-9()]*\\)*).*|[a-zA-Z]:\\((?:[a-zA-Z0-9()]*\\)*).*|/((?:[a-zA-Z0-9()]*\\)*).*''')


CONTINUATION = "\u200b\u200c\u200b"


def find_url(view, event=None, pt=None):
    if event:
        pt = view.window_to_text((event["x"], event["y"]))
    line = view.line(pt)

    line.a = max(line.a, pt - 1024)
    line.b = pt + 1024

    text = view.substr(line)
    text = text.replace(CONTINUATION + "\n", "")
    it = rex.finditer(text)

    for match in it:
        if match.start() <= (pt - line.a) and match.end() >= (pt - line.a):
            url = text[match.start():match.end()]
            return url

    return None


def find_url_region(view, event=None, pt=None):
    if event:
        pt = view.window_to_text((event["x"], event["y"]))
    line = view.line(pt)

    line.a = max(line.a, pt - 1024)
    line.b = pt + 1024

    text = view.substr(line)
    original_text = text
    text = text.replace(CONTINUATION + "\n", "")

    for match in rex.finditer(text):
        if match.start() <= (pt - line.a) and match.end() >= (pt - line.a):
            a = match.start()
            b = match.end()
            for marker in re.finditer(CONTINUATION + "\n", original_text):
                if a <= marker.start() and b >= marker.start():
                    b += len(CONTINUATION) + 1
            return (line.a + a, line.a + b)
    return None



class TerminusMouseEventListener(sublime_plugin.EventListener):

    def on_text_command(self, view, command_name, args):
        if command_name == "drag_select":
            if len(args) == 1 and args["event"]["button"] == 1:  # simple click
                return ("terminus_click", args)

    def on_hover(self, view, point, hover_zone):
        if hover_zone != sublime.HOVER_TEXT:
            return
        url = find_url(view, pt=point)
        # print(url)
        if not url:
            return

        if not os.path.exists(url):
           return

        def on_navigate(action):
            if action == "open":
                print('open:'+url)
                if os.path.exists(url) and not os.path.isdir(url):
                    sublime.active_window().open_file(url)
                else:
                    view.set_status('open:', "cannot find file:" + url)

        def on_hide():
            if link_key:
                view.erase_regions(link_key)

        url_region = find_url_region(view, pt=point)
        print(url_region)
        link_key = None
        if url_region:
            link_key = highlight_key(view)
            print("link_key:"+link_key)
            view.add_regions(
                link_key,
                [sublime.Region(*url_region)],
                "meta",
                flags=sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE)

        view.show_popup(
            URL_POPUP,
            sublime.HIDE_ON_MOUSE_MOVE_AWAY,
            location=point,
            on_navigate=on_navigate, on_hide=on_hide)

